/********************************
 * Robinson Matrix Algorithm
 *
 * Copyright (C) 2009 CNRS
 * Author : Florent AVELLANEDA, Eugen CEPOI
 *
 *
 * All rights reserved.
 *
 *   This file is part of Robinson Matrix Algorithm.
 *
 *   Robinson Matrix Algorithm is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   Robinson Matrix Algorithm is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with Robinson Matrix Algorithm.  If not, see <http://www.gnu.org/licenses/>.
 *
 ***********************************************************************************/
#ifndef MATRIX_J66BTRW4

#define MATRIX_J66BTRW4

#include <string>
#include <fstream>
#include <iostream>

#include <vector>
#include <set>

class Matrix
{
    public:
        Matrix ( );
        Matrix ( std::vector<std::vector<double> > m );
        /*
         * @brief this constructor creates a sub matrix of the Matrix m
         *
         * @param matrix - the main matrix
         * @param col - the sub matrix elements, same as in the mainMatrix
         */
        Matrix ( Matrix *m, std::vector<unsigned int> col );
        virtual ~Matrix ();


        /**
         * @brief set distance (d) from x to y
         *
         * @param x id node
         * @param y id node
         * @param d distance
         */
        void set(unsigned int x, unsigned int y, double d);

        /**
         * @brief Adds the two fictif bounds, which have "infinite" distance to the other elements
         */
        void setFictifBounds();

        /**
         * @brief Used to add an element from the main matrix in the current sub matrix
         */
        void setElementFromMainMatrix( unsigned int element );

        /**
         * @brief Removes the two fictif bounds
         */
        void removeFictifBounds();

        void setSize(unsigned int size);
        /**
         * @brief get distance from x to y
         *
         * @param x id node
         * @param y id node
         *
         * @return distance
         */
        inline double get(const unsigned int &x, const unsigned int &y) const
        {
            return _vvMatrix[x][y];
        }

        /**
         * @brief used to generate a random matrix
         */
        void randomGen(unsigned int size, int maxVal = 100);
        /**
         * @brief used to generate a random matrix
         */
        void randomGen2(unsigned int size, int maxVal = 100);
        /**
         * @brief used to generate a random matrix
         */
        void randomGen3(unsigned int size, double maxDelta = 0);
        /**
         * @brief used to generate a random robinson matrix
         */
        void randomRobinsonMatrix(unsigned int size);

        std::vector<unsigned int> getColsInMatrix();

        inline unsigned int getSize() const
        {
            return _vvMatrix.size();
        }

        void clean();
        /**
         * @brief show matrix (exemple for cout)
         *
         * @param os output stream
         * @param m matrix
         *
         * @return output stream
         */
        friend std::ostream& operator << (std::ostream& os, const Matrix& m);


        /**
         * @brief set matix by input stream (exemple for cin)
         *
         * @param os input stream
         * @param m matrix
         *
         * @return input stream
         */
        friend std::istream& operator >> (std::istream& os, Matrix& m);

    private:
        double _dMaxDist;
        std::vector<std::vector<double> > _vvMatrix;
        /**
         * @brief this vector contains the indexes of the elements from the main matrix, it's used to construct
         * the submatrix */
        std::vector<unsigned int> _colsInMatrix;
        /**
         * @brief this is the main matrix from wich we construct the submatrix */
        Matrix *_mainMatrix;
};

/**
 * Show matrix
 */
std::ostream& operator << (std::ostream& os, const Matrix& m);

/**
 * set matrix
 */
std::istream& operator >> (std::istream& is, Matrix& m);


#endif /* end of include guard: MATRIX_J66BTRW4 */
